#include "DX9Engine.h"

DX9Engine* DX9Engine::getInstance()
{
	static DX9Engine instance;
	return &instance;
}

void DX9Engine::initialize(HWND hWnd)
{
	// create the D3D interface
	m_pDX9Object = Direct3DCreate9(D3D_SDK_VERSION);
	// create a struct to hold various device information
	D3DPRESENT_PARAMETERS D3DParam;
	// clear out struct for use
	ZeroMemory(&D3DParam, sizeof(D3DParam));
	// windowed/fullscreen mode
	D3DParam.Windowed = TRUE;
	// discard old frames
	D3DParam.SwapEffect = D3DSWAPEFFECT_DISCARD;
	// set the window to be used by Direct3D
	D3DParam.hDeviceWindow = hWnd;
#ifdef FULLSCREEN_MODE
	// set the back buffer format to 32-bit
	D3DParam.BackBufferFormat = D3DFMT_X8R8G8B8;    
	// set the width of the buffer
	D3DParam.BackBufferWidth = SCREEN_WIDTH;    
	// set the height of the buffer
	D3DParam.BackBufferHeight = SCREEN_HEIGHT;   
#endif
	// create device class
	m_pDX9Object->CreateDevice(D3DADAPTER_DEFAULT,
								D3DDEVTYPE_HAL,
								hWnd,
								D3DCREATE_SOFTWARE_VERTEXPROCESSING,
								&D3DParam,
								&m_pDX9Device);
	// create sprite object
	D3DXCreateSprite(m_pDX9Device, &m_sprite);
	// initialize vector array of textures
	m_textures.init();

	// create font object
	// Load D3DXFont, each font style you want to support will need an ID3DXFont
	D3DXCreateFont( m_pDX9Device, 20, 0, FW_BOLD, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 
					DEFAULT_PITCH | FF_DONTCARE, TEXT("Courier New"), &m_pFont );
}

/** begin scene */
void DX9Engine::startRender()
{
	// clear the window to a deep blue
    m_pDX9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
    m_pDX9Device->BeginScene();    // begins the 3D scene 
}

/** end scene */
void DX9Engine::endRender()
{
	m_pDX9Device->EndScene();    // ends the 3D scene
    m_pDX9Device->Present(NULL, NULL, NULL, NULL);    // displays the created frame
}

/** start sprite */
void DX9Engine::startSprite()
{
	m_sprite->Begin(D3DXSPRITE_ALPHABLEND);		// begin sprite draw
}

/** end sprite */
void DX9Engine::endSprite()
{
	m_sprite->End();		// end sprite draw
}

/** draw sprite from template vector */
void DX9Engine::renderTexture(int index, V2DF pos, float scale, float angle, 
							  RECT* sheet, bool centered, int r, int g, int b)
{
	// check if sprite is to be centered
	if(centered)
	{
		D3DXVECTOR3 center;
		// check if sprite sheet exists
		if(sheet)
		{
			float x = sheet->right - sheet->left;
			float y = sheet->bottom - sheet->top;
			center = D3DXVECTOR3(x*0.5, y*0.5, 0.0f);
			m_sprite->Draw(m_textures.get(index)->sprite, sheet, &center, &D3DXVECTOR3(pos.x, pos.y, 0), D3DCOLOR_ARGB(255, r, g, b));
		}
		else
		{
			float x = m_textures.get(index)->imageInfo.Width*0.5;
			float y = m_textures.get(index)->imageInfo.Height*0.5;
			center = D3DXVECTOR3(x, y, 0.0f);
			m_sprite->Draw(m_textures.get(index)->sprite, 0, &center, &D3DXVECTOR3(pos.x, pos.y, 0), D3DCOLOR_ARGB(255, r, g, b));
		}
	}
	else
	{
		// check if sprite sheet exists
		if(sheet)
		{
			m_sprite->Draw(m_textures.get(index)->sprite, sheet, 0, &D3DXVECTOR3(pos.x, pos.y, 0), D3DCOLOR_ARGB(255, r, g, b));
		}
		else
		{
			m_sprite->Draw(m_textures.get(index)->sprite, 0, 0, &D3DXVECTOR3(pos.x, pos.y, 0), D3DCOLOR_ARGB(255, r, g, b));
		}
	}
}

/** Draw text to window 
 * @param text Text to be written to screen
 * @param rect Text bounds (location on screen)
 */
void DX9Engine::writeText(char * text, RECT rect)
{
	m_pFont->DrawTextA(0, text, -1, &rect, DT_TOP | DT_LEFT | DT_NOCLIP, m_fontColor);
}

/** Draw text centered at rect 
* @param text Text to be written to screen
* @param rect Text bounds (location on screen)
*/
void DX9Engine::writeTextCenter(char* text, RECT rect)
{
	m_pFont->DrawTextA(0, text, -1, &rect, DT_CENTER | DT_VCENTER, m_fontColor);
}

/** release COM objects */
void DX9Engine::release()
{
	for(int i=0; i<m_textures.size(); ++i)
		delete m_textures.get(i);
	m_textures.release();
	m_sprite->Release();
	m_pDX9Device->Release();
	m_pDX9Object->Release();
}

/**
 * resource manager for all textures
 * @return index of sprite
 */
int DX9Engine::createSprite(LPCWSTR file, int length)
{
	bool alreadyExists = false;
	int index = 0;

	// make sure this file has not been added prior
	for(int i = 0; i < m_textures.size() && !alreadyExists; ++i)
	{
		// first make sure they are even the same length
		if(length = m_textures.size())
		{
			// now compare the names
			for(int j = 0; j < length; ++j)
			{
				if( !(file == m_textures.get(i)->name) ){
					break;
				}
				// if the final char has been checked and is the same this texture already exists
				if(j == length-1)
				{
					index = i;
					alreadyExists = true;
				}
			}
		}
	}

	// now only load the texture if it doesn't already exist
	// if it does return the index of the one already created
	if(alreadyExists)
	{
		DbgPrintf("Texture index[%d] already exists\n", index);
		return index;
	}

	// first load up the texture from the given file
	TextureInfo *temp = new TextureInfo;

	// load texture
	D3DXCreateTextureFromFileEx(m_pDX9Device, file, D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, 
		D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 
			D3DCOLOR_XRGB(255, 0, 255), &temp->imageInfo, 0, &temp->sprite);
	
	// add its name and length
	temp->length = length;
	temp->name = file;

	// create bounds for texture
	RECT trect;
	trect.top = trect.left = 0;
	trect.right = temp->imageInfo.Width;
	trect.bottom = temp->imageInfo.Height;
	temp->rect = trect;

	// now attempt to add this file to the vector
	m_textures.add(temp);
	DbgPrintf("Texture index[%d] created\n", m_textures.size()-1);
	return m_textures.size()-1;
}